function Bits(bits) {
    'use strict';

    function throwsException( errorMessage, errorType, occuredAt ){
       var exception = {
            'occuredAt': (typeof occuredAt === 'undefined') ? 'Bits' : occuredAt,
            'errorType': (typeof errorType === 'undefined') ? 'Illegal Argument Exception' : errorType,
            'errorMessage': (typeof errorMessage === 'undefined') ? 'Undefined' : errorMessage
        };

        console.error( exception.errorType + "! " + exception.errorMessage + " " + exception.occuredAt );

        throw(exception);
    }

    if ( Object.prototype.toString.call(bits) === '[object Bits]' ) {
      return new Bits( bits.value );
    }

    if ( Object.prototype.toString.call(bits) === '[object Array]' ) {
        
        bits = bits.map( function(bit) { 
            if( typeof bit === 'boolean'){
                return bit; 
            } else if( bit === 0 || bit === '0' || bit.toUpperCase() === 'FALSE' || bit.toUpperCase() === 'F' ) {
                return false; 
            } else if( bit === 1 || bit === '1' || bit.toUpperCase() === 'TRUE'  || bit.toUpperCase() === 'T' ) {
                return true;
            } else {
                throwsException( 'Invalid Argument Exception', ('Failed to initialized Bits object with passed in "value" argument as a binary value!. Expected an array with boolean values, actual array was ' + bits + '.') );
            }
        } );
    }

    if ( typeof bits === 'number' ) {
        bits = bits.toString();
    }

    if( typeof bits === 'string' ) {
        
        var words = bits.split(' ');
        var isValidWords = words.every( 
            function(word) { 
                return ( word.toUpperCase() === 'TRUE' || word.toUpperCase() === 'FALSE'); 
            } 
        );

        if ( isValidWords ) {
            return new Bits( words.map( 
                function(word) {
                    if( word.toUpperCase() === 'TRUE' ) {
                        return true;
                    } else if( word.toUpperCase() === 'FALSE' ) {
                        return false;
                    } else {
                        throwsException();
                    }
                }
            ));
        }

        return new Bits( bits.trim().split('') );
    }

    this.value = bits;
    this.toString = function() { return '[object Bits]' };
    this.invert = function() { return new Bits( this.value.map( function(bit) { return (bit) ? false : true; } )); };
    this.getHighBits = function() { return new Bits( this.value.slice( (this.value.length / 2), this.value.length) ); };
    this.getLowBits = function() { return new Bits( this.value.slice( 0, (this.value.length / 2) ));};
}